#pragma once
#include <vector>
#include "..\utils\PlainTextReader.h"

namespace ds {

enum DeclarationType {
	DT_FLOAT,
	DT_INT,
	DT_VEC2,
	DT_COLOR,
	DT_VEC3,
	DT_STRING,
	DT_WORLD,
	DT_LAYER,
	DT_TEXTURE,
	DT_RENDER_TARGET,
	DT_SHADER,
	DT_SCREEN_QUAD,
	DT_PARTICLESYSTEM,
	DT_PARTICLE_AFFECTOR,
	DT_SOUND,
	DT_MENU_ACTION,
	DT_FONT
};

struct ResourceFile {
	std::string path;
	std::string fileName;
	std::string ending;
	std::string fqName;
	unsigned long size;
	FILETIME* fileTime;
	DeclarationType declarationType;
	bool reloadable;
};

class ResourceDeclaration {

public:
	ResourceDeclaration(const std::string& name) : m_Name(name) {}
	virtual ~ResourceDeclaration() {}
	virtual void parseCategory(Category* category) = 0;
	virtual DeclarationType getType() const = 0;	
	std::string& getName() {
		return m_Name;
	}
private:
	std::string m_Name;
};

class IntDecl : public ResourceDeclaration {

public:
	IntDecl(const std::string& name,int v) : ResourceDeclaration("IntDecl") , m_Name(name) , m_Value(v) {}
	virtual ~IntDecl() {}
	void parseCategory(Category* category) {}
	DeclarationType getType() const {
		return DT_INT;
	}
	int getValue() {
		return m_Value;
	}
	std::string& getName() {
		return m_Name;
	}
private:
	std::string m_Name;
	int m_Value;
};

class FloatDecl : public ResourceDeclaration {

public:
	FloatDecl(const std::string& name,float v) : ResourceDeclaration("FloatDecl") , m_Name(name) , m_Value(v) {}
	virtual ~FloatDecl() {}
	void parseCategory(Category* category) {}
	DeclarationType getType() const {
		return DT_FLOAT;
	}
	float getValue() {
		return m_Value;
	}
	std::string& getName() {
		return m_Name;
	}
private:
	std::string m_Name;
	float m_Value;
};

class Vec2Decl : public ResourceDeclaration {

public:
	Vec2Decl(const std::string& name,const Vec2& v) : ResourceDeclaration("Vec2Decl") , m_Name(name) , m_Value(v) {}
	~Vec2Decl() {}
	void parseCategory(Category* category) {}
	DeclarationType getType() const {
		return DT_VEC2;
	}
	Vec2& getValue() {
		return m_Value;
	}
	std::string& getName() {
		return m_Name;
	}
private:
	std::string m_Name;
	Vec2 m_Value;
};

class Vec3Decl : public ResourceDeclaration {

public:
	Vec3Decl(const std::string& name,const Vec3& v) : ResourceDeclaration("Vec3Decl") , m_Name(name) , m_Value(v) {}
	~Vec3Decl() {}
	void parseCategory(Category* category) {}
	DeclarationType getType() const {
		return DT_VEC3;
	}
	Vec3& getValue() {
		return m_Value;
	}
	std::string& getName() {
		return m_Name;
	}
private:
	std::string m_Name;
	Vec3 m_Value;
};

class ColorDecl : public ResourceDeclaration {

public:
	ColorDecl(const std::string& name,const Color& v) : ResourceDeclaration("ColorDecl") , m_Name(name) , m_Value(v) {}
	virtual ~ColorDecl() {}
	void parseCategory(Category* category) {}
	DeclarationType getType() const {
		return DT_COLOR;
	}
	Color& getValue() {
		return m_Value;
	}
	std::string& getName() {
		return m_Name;
	}
private:
	std::string m_Name;
	Color m_Value;
};

class StringDecl : public ResourceDeclaration {

public:
	StringDecl(const std::string& name,const std::string& v) : ResourceDeclaration("StringDecl") , m_Name(name) , m_Value(v) {}
	~StringDecl() {}
	void parseCategory(Category* category) {}
	DeclarationType getType() const {
		return DT_STRING;
	}
	std::string& getValue() {
		return m_Value;
	}
	std::string& getName() {
		return m_Name;
	}
private:
	std::string m_Name;
	std::string m_Value;
};

class DeclarationManager;

class DeclarationParser {

public:
	virtual ResourceDeclaration* loadTextFile(const ResourceFile& resourceFile) = 0;
	virtual void loadTextFile(const ResourceFile& resourceFile,DeclarationManager* declarationManager) = 0;
	virtual void createResource(ResourceDeclaration* declaration) = 0;
	virtual DeclarationType getType() const = 0;	
	virtual bool isSupported(const std::string& fileEnding) const = 0;
	virtual bool isReloadable() const = 0;
};

class DeclarationManager {

typedef std::vector<DeclarationParser*> Parsers;
typedef std::vector<ResourceDeclaration*> Declarations;
typedef std::vector<ResourceFile> ResourceFiles;

public:
	DeclarationManager(float reloadDelay = 1.0f);
	~DeclarationManager(void);
	void processDirectory(const std::string& dir);
	void createResources();
	void checkFiles(float elapsed);
	ResourceDeclaration* getDeclaration(const std::string& name);
	void addDeclaration(ResourceDeclaration* resourceDeclaration) {
		m_Declarations.push_back(resourceDeclaration);
	}
	void debug();
private:
	DeclarationParser* getParserByType(DeclarationType type);
	DeclarationParser* getParserByEnding(const std::string& ending);
	void scanDirectories(const std::string& baseDir,std::vector<ResourceFile>& files);
	std::string translateDeclType(DeclarationType type);
	float m_Timer;
	float m_ReloadDelay;
	Parsers m_Parsers;
	ResourceFiles m_Files;
	Declarations m_Declarations;
};

}

